import sys, os, random, requests
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
    QScrollArea, QLabel, QTextEdit, QFileDialog, QGridLayout, QFrame
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QUrl
from PyQt5.QtGui import QPixmap, QDesktopServices
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from bs4 import BeautifulSoup
from pathlib import Path
from urllib.parse import urlparse, unquote


# -------------------- Helper --------------------
def get_media_src(parent_tag):
    video_tag = parent_tag.find("video")
    if video_tag and (video_tag.get("src") or video_tag.get("data-src")):
        return {"src": video_tag.get("src") or video_tag.get("data-src"), "type": "video"}
    img_tag = parent_tag.find("img")
    if img_tag and (img_tag.get("src") or img_tag.get("data-src")):
        return {"src": img_tag.get("src") or img_tag.get("data-src"), "type": "image"}
    return None


def parse_items(page):
    url = "https://haowallpaper.com/homeView" if page == 1 else f"https://haowallpaper.com/homeView?isSel=true&page={page}"
    resp = requests.get(url, timeout=15)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "html.parser")
    return [m for item in soup.find_all("div", class_="card") if (m := get_media_src(item))]


def safe_filename_from_url(url, prefer_ext=None):
    parsed = urlparse(url)
    path = unquote(parsed.path)
    base = os.path.basename(path) or "file"
    name, ext = os.path.splitext(base)
    if not ext: ext = f".{prefer_ext}" if prefer_ext else ""
    safe_name = "".join(c for c in name if c.isalnum() or c in ("_", "-", " ")).rstrip() or "file"
    return f"{safe_name}{ext}"


# -------------------- Worker --------------------
class FetchThread(QThread):
    finished = pyqtSignal(list, int)
    error = pyqtSignal(str)

    def __init__(self, page):
        super().__init__();
        self.page = page

    def run(self):
        try:
            # items = parse_items(self.page)
            # print(type(items))
            # page = random.randint(1, 2019)
            # print(parse_items(page))
            items = []
            for i in range(0, 2):
                page = random.randint(1, 2019)
                items + parse_items(page)
                print(items)
            self.finished.emit(items, self.page)
            print(items)
        except Exception as e:
            self.error.emit(str(e))


class DownloadThread(QThread):
    progress = pyqtSignal(str)
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, item, folder):
        super().__init__();
        self.item = item;
        self.folder = folder

    def run(self):
        try:
            self.progress.emit(f"开始下载 {self.item['type']} ...")
            r = requests.get(self.item["src"], stream=True, timeout=30)
            r.raise_for_status()
            ext = "mp4" if self.item["type"] == "video" else "png"
            filename = safe_filename_from_url(self.item["src"], ext)
            path = Path(self.folder) / filename
            with open(path, "wb") as f:
                for chunk in r.iter_content(8192):
                    if chunk: f.write(chunk)
            self.finished.emit(str(path))
        except Exception as e:
            self.error.emit(str(e))


class ImageLoadThread(QThread):
    finished = pyqtSignal(QPixmap, object)  # pixmap, item
    error = pyqtSignal(object)

    def __init__(self, item):
        super().__init__();
        self.item = item

    def run(self):
        try:
            data = requests.get(self.item["src"], timeout=10).content
            pix = QPixmap()
            pix.loadFromData(data)
            pix = pix.scaled(QSize(220, 180), Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.finished.emit(pix, self.item)
        except:
            self.error.emit(self.item)


# -------------------- Main Window --------------------
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Wallpaper/Video Downloader")
        self.resize(1000, 700)
        self.items = []
        self.download_dir = str(Path.home() / "Desktop" / "wallpaper")
        os.makedirs(self.download_dir, exist_ok=True)
        self.video_players = []  # 视频播放器列表
        self._setup_ui()
        self.first_show = True  # 标记第一次显示

    def showEvent(self, event):
        super().showEvent(event)
        if self.first_show:
            self.first_show = False
            self.on_fetch()  # 启动时自动抓取

    def _setup_ui(self):
        main_layout = QVBoxLayout(self)
        # 顶部按钮
        btn_layout = QHBoxLayout()
        self.fetch_btn = QPushButton("随机抓取页面");
        self.fetch_btn.clicked.connect(self.on_fetch)
        self.choose_btn = QPushButton("选择下载目录");
        self.choose_btn.clicked.connect(self.on_choose_dir)
        btn_layout.addWidget(self.fetch_btn);
        btn_layout.addWidget(self.choose_btn);
        btn_layout.addStretch()
        main_layout.addLayout(btn_layout)

        # 上半部分滚动区域
        self.scroll_area = QScrollArea();
        self.scroll_area.setWidgetResizable(True)
        self.result_container = QWidget()
        self.grid_layout = QGridLayout(self.result_container);
        self.grid_layout.setSpacing(10)
        self.scroll_area.setWidget(self.result_container)
        main_layout.addWidget(self.scroll_area, 4)

        # 下半部分日志
        self.log = QTextEdit();
        self.log.setReadOnly(True)
        main_layout.addWidget(self.log, 1)

    def log_msg(self, msg):
        self.log.append(msg)

    def on_choose_dir(self):
        d = QFileDialog.getExistingDirectory(self, "选择下载目录", self.download_dir)
        if d: self.download_dir = d; self.log_msg(f"下载目录: {d}")

    def on_fetch(self):
        page = random.randint(1, 2019)
        self.log_msg(f"抓取页面 {page} 中...")
        self.fetch_btn.setEnabled(False)
        self.thread = FetchThread(page)
        self.thread.finished.connect(self.on_fetch_done)
        self.thread.error.connect(self.on_fetch_error)
        self.thread.start()

    def on_fetch_done(self, items, page):
        self.fetch_btn.setEnabled(True)
        self.items = items

        # 清理旧控件和视频播放器
        for i in reversed(range(self.grid_layout.count())):
            w = self.grid_layout.itemAt(i).widget()
            if w: w.deleteLater()
        for player in self.video_players:
            player.stop();
            player.deleteLater()
        self.video_players.clear()

        # 统计图片和视频数量
        img_count = sum(1 for it in items if it["type"] == "image")
        video_count = sum(1 for it in items if it["type"] == "video")
        self.log_msg(f"抓取完成，共 {len(items)} 条 (页面 {page})，图片 {img_count} 个，视频 {video_count} 个")

        # 展示结果
        cols = 4
        self.image_threads = []
        for idx, it in enumerate(items):
            frame = QFrame();
            frame.setFrameShape(QFrame.StyledPanel)
            vbox = QVBoxLayout(frame)
            r = idx // cols;
            c = idx % cols
            self.grid_layout.addWidget(frame, r, c)

            if it["type"] == "image":
                thread = ImageLoadThread(it)
                thread.finished.connect(lambda pix, item, f=frame: self.display_image(pix, f, item))
                thread.error.connect(lambda item: self.log_msg(f"❌ 图片加载失败: {item['src']}"))
                thread.start()
                self.image_threads.append(thread)
            else:
                # 视频预览
                video_widget = QVideoWidget()
                video_widget.setMinimumSize(220, 180)
                vbox.addWidget(video_widget)
                media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
                media_player.setMedia(QMediaContent(QUrl(it["src"])))
                media_player.setVideoOutput(video_widget)
                media_player.setMuted(True)
                media_player.play()
                self.video_players.append(media_player)

                # 点击视频下载
                video_widget.mousePressEvent = lambda e, item=it: self.download_item(item)

    def display_image(self, pix, frame, item):
        label = QLabel()
        label.setPixmap(pix)
        label.setAlignment(Qt.AlignCenter)
        frame.layout().addWidget(label)
        label.mousePressEvent = lambda e: self.download_item(item)

    def on_fetch_error(self, err):
        self.fetch_btn.setEnabled(True)
        self.log_msg(f"❌ 错误: {err}")

    def download_item(self, item):
        self.log_msg(f"准备下载 {item['type']}")
        self.dthread = DownloadThread(item, self.download_dir)
        self.dthread.progress.connect(self.log_msg)
        self.dthread.finished.connect(lambda p: self.log_msg(f"下载完成: {p}"))
        self.dthread.error.connect(lambda e: self.log_msg(f"下载失败: {e}"))
        self.dthread.start()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
